package com.sls.game.service.impl;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.google.gson.Gson;
import com.sls.core.common.CommonUtil;
import com.sls.core.http.HttpClient;
import com.sls.core.socket.Head;
import com.sls.core.socket.ServerDisponseException;
import com.sls.core.util.PropertiesUtil;
import com.sls.core.util.ServerDateAndTime;
import com.sls.core.util.UtilMD5Encryption;
import com.sls.game.common.DeductionRefund;
import com.sls.game.constant.ExceptionCodeDes;
import com.sls.game.dao.DownstreamUserDAO;
import com.sls.game.dao.GoodsOrderDAO;
import com.sls.game.dao.yun.YunDAO;
import com.sls.game.page.Pagination;
import com.sls.game.parser.ParseYunRespInfo;
import com.sls.game.parser.sls.OrderStatusSendParse;
import com.sls.game.pojo.DeductionRefundInfo;
import com.sls.game.pojo.DownstreamUserInfo;
import com.sls.game.pojo.GoodsOrderInfo;
import com.sls.game.pojo.SLSHttpInterfaceInfo;
import com.sls.game.pojo.yunen.YunEnProduct;
import com.sls.game.pojo.yunen.YunEnRespInfo;
import com.sls.game.service.YunService;

@Service("yunService")
public class YunServiceImpl implements YunService {

	private static Logger log = Logger.getLogger(YunServiceImpl.class);
	private static String filename = "yunen.properties";
	private Gson gson;
	@Resource(name = "yunDAO")
	private YunDAO yunDAO;
	@Resource(name = "goodsOrderDAO")
	private GoodsOrderDAO goodsOrderDAO;
	@Resource(name = "downstreamUserDAO")
	private DownstreamUserDAO downstreamUserDAO;

	public YunServiceImpl() {
		gson = CommonUtil.gson();
	}

	@Override
	public void save(String body, Head head) {
		YunEnProduct product = gson.fromJson(body, YunEnProduct.class);
		product.setId(UUID.randomUUID().toString());
		product.setInsertTime(ServerDateAndTime.getNowDateTimeOfFormat());
		product.setIsAudit("0");
		this.yunDAO.insert(product);

	}

	@Override
	public void update(String body, Head head) {
		YunEnProduct product = gson.fromJson(body, YunEnProduct.class);
		product.setIsAudit("0");
		product.setModifyTime(ServerDateAndTime.getNowDateTimeOfFormat());
		this.yunDAO.update(product);
	}

	@Override
	public YunEnProduct queryById(String body, Head head) {
		String id = gson.fromJson(body, String.class);
		YunEnProduct pro = this.yunDAO.queryById(id);
		return pro;
	}

	@Override
	public Pagination<YunEnProduct> queryPage(String body, Head head) {
		YunEnProduct product = gson.fromJson(body, YunEnProduct.class);
		Pagination<YunEnProduct> page = this.yunDAO.queryPage(product);
		return page;
	}

	@Override
	public void updateOrderStatus(String body, Head head) {
		YunEnRespInfo asyncInfo = gson.fromJson(body, YunEnRespInfo.class);
		// 成功处理时间
		String orderSuccessTime = ServerDateAndTime.getNowDateTime();
		String orderSuccessTime2 = ServerDateAndTime.getNowDateTimeOfFormat();
		boolean flag = this.checkData(asyncInfo);
		if (flag) {
			// 主动通知下游用户
			String userhandleResult = sendNotifyToDownUserMsg(asyncInfo,
					orderSuccessTime, head);
			updateGoodsOrder(head, asyncInfo, orderSuccessTime2,
					userhandleResult);
		}
	}

	private void updateGoodsOrder(Head head, YunEnRespInfo asyncInfo,
			String orderSuccessTime, String userhandleResult) {
		// sls订单编号
		String orderNo = asyncInfo.getOrderId();
		// SUP平台订单号
		String supOrderNo = asyncInfo.getYunenOrderId();
		// 订单交易状态
		String statusCode = asyncInfo.getOrderStatus();

		GoodsOrderInfo goodsOrderInfo = new GoodsOrderInfo();
		goodsOrderInfo.setOrderId(orderNo);
		goodsOrderInfo.setSupOrderId(supOrderNo);

		String status = "1";
		if ("SUCCESS".equals(statusCode)) { // 成功
			status = "1";
		} else { // 失败
			status = "0";
			// 退款操作
			DeductionRefundInfo dedInfo = null;
			dedInfo = DeductionRefund.refundWhenAsynCallBackFailed(orderNo,
					goodsOrderDAO, head);
			String paymentStatus = "";
			if (dedInfo != null) {
				paymentStatus = dedInfo.getPaymentStatus();
			}
			if ("1".equals(paymentStatus)) { // 成功
				goodsOrderInfo.setIsPay("3"); // 退款成功
				// 退款成功，通知下游用户
				DeductionRefund.noticeUserRefundMsg(orderNo, dedInfo,
						goodsOrderDAO, downstreamUserDAO, null);

			} else if ("2".equals(paymentStatus)) {
				GoodsOrderInfo orderInfo = goodsOrderDAO
						.queryByOrderId(orderNo);
				if (orderInfo != null) {
					String isPayValue = orderInfo.getIsPay(); // 支付状态值
					if ("1".equals(isPayValue)) {
						goodsOrderInfo.setIsPay("2"); // 退款失败
					}
				}
			}
		}
		goodsOrderInfo.setStatus(status);
		goodsOrderInfo.setSupOrderSuccessTime(orderSuccessTime);
		goodsOrderInfo.setUserhandleResult(userhandleResult);
		goodsOrderInfo.setSynOrAsy("1"); // 异步推送
		// 数据更新
		try {
			goodsOrderDAO.update(goodsOrderInfo);
		} catch (Exception e) {
			log.error("云恩异步推送更新订单异常", e);
			throw new ServerDisponseException(
					ExceptionCodeDes.ACCESS_DATABASE_ERROR.getCode(),
					ExceptionCodeDes.ACCESS_DATABASE_ERROR.getDescription());
		}

	}

	private String sendNotifyToDownUserMsg(YunEnRespInfo asyncInfo,
			String orderSuccessTime, Head head) {
		String handleResult = "FAILED";
		String orderId = asyncInfo.getOrderId();
		GoodsOrderInfo orderInfo = this.goodsOrderDAO.queryByOrderId(orderId);
		String notifyUrl = "";
		// 下游用户编号
		String contractId = null;
		if (orderInfo != null) {
			notifyUrl = orderInfo.getNotifyUrl();
			contractId = orderInfo.getContractId();

			String secretKey = null; // 下游用户密钥
			DownstreamUserInfo downstreamUserInfo = downstreamUserDAO
					.queryUserByUserNO(contractId);
			if (downstreamUserInfo != null) {
				secretKey = downstreamUserInfo.getSecretKey();
			}
			String httpUrl = notifyUrl
					+ "?"
					+ this.assembleParameter(asyncInfo, orderInfo, secretKey,
							orderSuccessTime);

			HttpClient httpClient = new HttpClient();
			// 供应商返回消息编码方式
			String supplyEncode = "UTF-8";
			// 给下游发消息
			String xmlStr = "";
			try {
				log.info("请求ID：" + head.getRequestId() + "，异步回调给下游用户的url："
						+ httpUrl);
				xmlStr = httpClient.doGet(httpUrl, supplyEncode);
				log.info("请求ID：" + head.getRequestId() + "，下游用户的返回结果：" + xmlStr);
			} catch (Exception e) {
				log.error("请求ID：" + head.getRequestId() + "，主动通知下游用户出现异常！", e);
			}
			if (xmlStr != null && !("".equals(xmlStr))) {
				SLSHttpInterfaceInfo slsInfo = null;
				slsInfo = OrderStatusSendParse.readUserSendMsg(xmlStr);
				if (slsInfo != null) {
					handleResult = slsInfo.getHandleResult();
				}
			}
		}
		return handleResult;
	}

	private String assembleParameter(YunEnRespInfo asyncInfo,
			GoodsOrderInfo orderInfo, String secretKey, String orderSuccessTime) {
		// 下游用户订单号
		String ptOrderNo = orderInfo.getMerchantOrderId();
		// 手拉手订单号
		String supOrderNo = asyncInfo.getOrderId();
		// 充值后状态
		String orderState = asyncInfo.getOrderStatus();
		String err_msg = "";

		StringBuilder strBui = new StringBuilder();
		strBui.append("ptOrderNo=");
		strBui.append(ptOrderNo);
		strBui.append("&");
		strBui.append("supOrderNo=");
		strBui.append(supOrderNo);
		strBui.append("&");
		strBui.append("status=");
		String status = null;
		if ("SUCCESS".equals(orderState)) { // 成功
			status = "ORDER_SUCCESS";
		} else { // 失败
			status = "ORDER_FAILED"; // ---------失败
		}
		strBui.append(status);
		strBui.append("&");

		if ("ORDER_SUCCESS".equals(status)) { // ---------订单成功，才传成功充值时间
			strBui.append("supOrderSuccessTime=");
			strBui.append(orderSuccessTime);
			strBui.append("&");
		} else { // ---------------------订单失败时，才传错误码
			strBui.append("failedReason=");
			String fr = "";
			if (StringUtils.isNotBlank(err_msg)) {
				try {
					fr = URLEncoder.encode(err_msg, "UTF-8");
				} catch (UnsupportedEncodingException e) {
					log.error("编码异常", e);
				}
			}
			strBui.append(fr);
			strBui.append("&");
		}

		strBui.append("sign=");
		String sign = createSign(ptOrderNo, supOrderNo, status,
				orderSuccessTime, err_msg, secretKey);
		strBui.append(sign);
		log.info("异步发送给下游用户的订单处理结果    \n 合作方订单编号:" + ptOrderNo + "\n 订单编号:"
				+ supOrderNo + "\n 订单最终处理结果：" + status + "\n订单处理的时间:"
				+ orderSuccessTime + "\n失败原因：" + err_msg);

		String result = strBui.toString().trim();
		return result;

	}

	private String createSign(String ptOrderNo, String supOrderNo,
			String status, String orderSuccessTime, String err_msg,
			String secretKey) {
		StringBuilder strBui = new StringBuilder();
		strBui.append(ptOrderNo);
		strBui.append(supOrderNo);
		strBui.append(status);
		if (orderSuccessTime != null && !("".equals(orderSuccessTime))) {
			strBui.append(orderSuccessTime);
		}
		if (err_msg != null && !("".equals(err_msg))) {
			strBui.append(err_msg);
		}
		strBui.append(secretKey);
		String data = strBui.toString().trim();
		String result = UtilMD5Encryption.createMD5Encryption(data);
		return result;
	}

	private boolean checkData(YunEnRespInfo asyncInfo) {
		boolean flag = false;
		if (StringUtils.isEmpty(asyncInfo.getYunenOrderId())) {
			throw new ServerDisponseException(
					ExceptionCodeDes.COOPERATION_PLATFORM_ORDERNO_NULL
							.getCode(),
					ExceptionCodeDes.COOPERATION_PLATFORM_ORDERNO_NULL
							.getDescription());
		} else if (StringUtils.isEmpty(asyncInfo.getOrderId())) {
			throw new ServerDisponseException(
					ExceptionCodeDes.SLS_ORDERNO_NULL.getCode(),
					ExceptionCodeDes.SLS_ORDERNO_NULL.getDescription());
		} else if (StringUtils.isEmpty(asyncInfo.getOrderStatus())) {
			throw new ServerDisponseException(
					ExceptionCodeDes.EN_LINK_RESULTCODE_EMPTY.getCode(),
					ExceptionCodeDes.EN_LINK_RESULTCODE_EMPTY.getDescription());
		} else {
			flag = true;
		}
		return flag;
	}

	@Override
	public YunEnRespInfo queryOrder(String body, Head head) {
		YunEnRespInfo reqInfo = gson.fromJson(body, YunEnRespInfo.class);
		if (reqInfo == null) {
			throw new ServerDisponseException(
					ExceptionCodeDes.PARSE_REQUEST_ERROR.getCode(),
					ExceptionCodeDes.PARSE_REQUEST_ERROR.getDescription());
		}
		String orderId = reqInfo.getOrderId();
		if (StringUtils.isEmpty(orderId)) {
			throw new ServerDisponseException(
					ExceptionCodeDes.SLS_ORDERNO_NULL.getCode(),
					ExceptionCodeDes.SLS_ORDERNO_NULL.getDescription());
		}

		YunEnRespInfo respInfo = null;
		String oi = orderId.trim();
		String address = PropertiesUtil.getValue(
				"yunen.interface.query.order.address", filename);
		String md5key = PropertiesUtil.getValue("yunen.md5.key", filename);
		String merchantId = PropertiesUtil.getValue("yunen.merchant.id",
				filename);
		String platformId = PropertiesUtil.getValue("yunen.platform.id",
				filename);
		String version = PropertiesUtil.getValue("yunen.version", filename);
		HttpClient httpClient = new HttpClient();
		StringBuilder sb = new StringBuilder();
		sb.append("merchant_id=");
		sb.append(merchantId);
		sb.append("&");
		sb.append("outer_order_id=");
		sb.append(oi);
		sb.append("&");
		sb.append("platform_id=");
		sb.append(platformId);
		sb.append("&");
		sb.append("version=");
		sb.append(version);
		sb.append("&");
		sb.append("key=");
		sb.append(md5key);
		String data = sb.toString();
		String sign = UtilMD5Encryption.createMD5Encryption(data);
		Map<String, String> map = new HashMap<String, String>();
		
		map.put("merchant_id", merchantId);
		map.put("platform_id", platformId);
		map.put("outer_order_id", oi);
		map.put("sign", sign);
		map.put("version", version);
		try {
			log.info("请求ID：" + head.getRequestId() + "--发送到云恩订单查询的请求参数："
					+ address + map);
			String xmlStr = httpClient.doPost(address, map);
			log.info("请求ID：" + head.getRequestId() + "--云恩返回的请求结果："
					+ xmlStr);
			if (StringUtils.isNotEmpty(xmlStr)) {
				respInfo = ParseYunRespInfo.getInfoOfRecharge(xmlStr);
			}
		} catch (Exception e) {
			log.error("请求ID：" + head.getRequestId() + "--云恩订单查询请求异常！", e);
		}
		return respInfo;

	}

}
